package com.inspur.cloud.service.dataspace;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.inspur.cloud.configuration.AmbariConfig;
import com.inspur.cloud.exception.ApiException;
import com.inspur.cloud.util.Base64Util;
import org.apache.commons.httpclient.HttpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * @author
 * @ClassName: RangerRestService
 * @Description: (通过API访问ranger拿需要的数据)
 * @date
 */
@Component
public class RangerRestService {

    protected static final Logger logger = LoggerFactory.getLogger(RangerRestService.class);

    @Autowired
    private AmbariConfig ambariConfig;
    @Autowired
    private ClusterConfigUtil clusterConfigUtil;
    @Autowired
    private RangerService rangerService;

    private String getRangerurl() {
        Map map = clusterConfigUtil.getRangerConfig();
        return "http://" + map.get("host_name") + ":" + map.get("ranger.service.http.port");
    }


    /**
     * @param
     * @return Map<String, Object>    返回类型
     * @throws
     * @Title: result
     * @Description: 封闭http请求
     */
    private Map<String, Object> result(HttpURLConnection conn, boolean input) {
        Map<String, Object> result = new HashMap<>();
        try{
            String authorization = "Basic " + Base64Util.getBase64(ambariConfig.getRangerServerUser() + ":" + ambariConfig.getRangerServerPass());
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Authorization", authorization);
            StringBuffer sb = new StringBuffer();
            if (input) {
                String line = null;
                try(InputStream is = conn.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(
                            is, "utf-8"))) {
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                }
            }
            int code = conn.getResponseCode();
            result.put("code", Integer.toString(code));
            result.put("msg", conn.getResponseMessage());
            result.put("type", conn.getContentType());
            result.put("data", sb.toString());

        }catch (Exception e){
            logger.warn("RangerRestService result URL ["+ conn.getURL() +"] catches exception.");
        }
        return result;
    }

    /**
     * @param
     * @return boolean    返回类型
     * @throws
     * @Title: getUserByName
     * @Description: 调用Ranger接口判断Ranger用户是否存在
     */
    public boolean getUserByName(String userName) {
        try {
            URL url = new URL(getRangerurl() + "/service/xusers/users?name=" + userName);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                String data = (String) map.get("data");
                JSONObject jo = JSONObject.parseObject(data);
                if (jo.get("vXUsers") != null) {
                    JSONArray ja = jo.getJSONArray("vXUsers");
                    Iterator<Object> it = ja.iterator();
                    while (it.hasNext()) {
                        JSONObject userInfo = (JSONObject) it.next();
                        if (userInfo.getString("name").equalsIgnoreCase(userName)) {
                            return true;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getUserByName name[" + userName + "]");
        }
        return false;
    }

    /**
     * @param
     * @return boolean    返回类型
     * @throws
     * @Title: getGroupByName
     * @Description: 调用Ranger接口判断Ranger用户组是否存在
     */
    public boolean getGroupByName(String userName) {
        try {
            URL url = new URL(getRangerurl() + "/service/xusers/groups?name=" + userName);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                String data = (String) map.get("data");
                JSONObject jo = JSONObject.parseObject(data);
                if (jo.get("vXGroups") != null) {
                    JSONArray ja = jo.getJSONArray("vXGroups");
                    Iterator<Object> it = ja.iterator();
                    while (it.hasNext()) {
                        JSONObject userInfo = (JSONObject) it.next();
                        if (userInfo.getString("name").equalsIgnoreCase(userName)) {
                            return true;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getGroupByName name[" + userName + "]");
        }
        return false;
    }

    /**
     * @param
     * @return boolean    返回类型
     * @throws
     * @Title: isExistUser
     * @Description: 综合判断用户或用户名是否存在
     */
    public boolean isExistUser(String userName) {
        if (getGroupByName(userName) || getUserByName(userName)) {
            return true;
        }
        return false;
    }

    /**
     * @param id
     * @return Map<String, Object>
     * @throws HttpException
     * @throws IOException
     * @Description: 根据id删除policy
     */
    public Map<String, Object> delPolicy(String id) throws HttpException, IOException {
        URL url = new URL(getRangerurl() + "/service/public/v2/api/policy/" + id);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("DELETE");
        String authorization = "Basic " + Base64Util.getBase64(ambariConfig.getRangerServerUser() + ":" + ambariConfig.getRangerServerPass());
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Authorization", authorization);
        Map<String, Object> result = new HashMap<>();
        int code = conn.getResponseCode();
        if (204 != code) {
            logger.error("statuscode[" + code + "], response[" + conn.getResponseMessage() + "]");
        }

        result.put("code", Integer.toString(code));
        result.put("msg", conn.getResponseMessage());

        return result;
    }

    /**
     * @param name
     * @return Map<String, Object>
     * @throws HttpException
     * @throws IOException
     * @Description: 根据用户名删除用户
     */
    public void delUser(String name) throws HttpException, IOException {
        URL url = new URL(getRangerurl() + "/service/xusers/users/userName/" + name+ "?forceDelete=true");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("DELETE");
        String authorization = "Basic " + Base64Util.getBase64(ambariConfig.getRangerServerUser() + ":" + ambariConfig.getRangerServerPass());
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Authorization", authorization);
        int code = conn.getResponseCode();
        if (204 != code) {
            logger.error("statuscode[" + code + "], response[" + conn.getResponseMessage().toString() + "]");
        }
    }

    /**
     * @param groupName
     * @return Map<String, Object>
     * @throws HttpException
     * @throws IOException
     * @Description: 根据用户组名删除组
     */
    public void delGroup(String groupName) throws HttpException, IOException {
        URL url = new URL(getRangerurl() + "/service/xusers/groups/groupName/" + groupName + "?forceDelete=true");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("DELETE");
        String authorization = "Basic " + Base64Util.getBase64(ambariConfig.getRangerServerUser() + ":" + ambariConfig.getRangerServerPass());
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Authorization", authorization);
        int code = conn.getResponseCode();
        if (204 != code) {
            logger.error("statuscode[" + code + "], response[" + conn.getResponseMessage().toString() + "]");
        }

    }

    /**
     * 获取Ranger中所有的策略
     *
     * @return
     */
    public String getAllPolicy() {
        String data = "";
        try {
            URL url = new URL(getRangerurl() + "/service/public/v2/api/policy");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                data = (String) map.get("data");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getAllpolicy error.");
        }
        return data;
    }

    /**
     * 根据服务名获取Ranger中所有的策略，如只获取所有HDFS的策略信息
     * 这里的serviceName是服务名，如cluster_101_hadoop
     *
     * @return
     */
    public String getPolicyByService(String serviceName) {
        String data = "";
        try {
            URL url = new URL(getRangerurl() + "/service/public/v2/api/service/" + serviceName + "/policy/");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                data = (String) map.get("data");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getPolicyByService serviceName[" + serviceName + "] error.");
        }
        return data;
    }


    /**
     * 根据服务名和策略名称获取某一条策略
     * 这里的serviceName是服务名，如cluster_101_hadoop
     * policyName是策略名，如public|share1
     *
     * @return
     */
    public String getPolicyByServiceNameAndPolicyName(String serviceName, String policyName) {
        String data = "";
        try {
            //策略名称中包含特殊字串，使用编码替代
            policyName = policyName.replace("|","%7C").replace(" ","%20");
            URL url = new URL(getRangerurl() + "/service/public/v2/api/service/" + serviceName + "/policy/" + policyName);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            //404未找到，说明没有对应的策略
            if (map.isEmpty()) {
                return data;
            }
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                data = (String) map.get("data");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getPolicyByServiceNameAndPolicyName serviceName[" + serviceName + "] error.");
        }
        return data;
    }

    /**
     * 根据id拿策略中的内容
     *
     * @param id
     * @return
     */
    public String getPolicyById(String id) {
        String data = "";
        try {
            URL url = new URL(getRangerurl() + "/service/public/v2/api/policy/" + id);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                data = (String) map.get("data");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getPolicyById id[" + id + "] error.");
        }
        return data;
    }

    /**
     * 根据某个资源值判断Ranger中是否已经存在对应的策略了
     *
     * @param service  传递过来的简易名称,如hdfs
     * @param resource 传递过来的资源值
     *                 如果是hdfs则resoure是路径如/user/test
     *                 如果是hbase则resource是表|列族|列
     *                 如果是hive则
     *                 如果是yarn则
     *                 如果是kafka则
     * @return
     */
    public int getPolicyIdByResourceItems(String service, String resource) {
        //如果不存在，返回-1，即代表新建策略
        int policyId = -1;
        //获取ranger某个服务内的所有策略
        String serviceName = getServiceName(service);
        String policyData = getPolicyByService(serviceName);
        if ("".equals(policyData)) {
            logger.error("获取Ranger：" + service + "服务中策略异常！");
        }
        //ranger中的策略遍历
        JSONArray array = JSONArray.parseArray(policyData);
        Iterator<Object> it = array.iterator();
        while (it.hasNext()) {
            JSONObject policy = (JSONObject) it.next();
            //ranger中的策略中的资源值
            JSONObject tmpResource = policy.getJSONObject("resources");
            //判断资源值中是否包含多个资源
            if (!isSingleResource(service, tmpResource)) {
                continue;
            }
            //将资源值转为字符串
            String tmpResourceString = resourceFormater(service, tmpResource);

            //判断两个资源值是否相等
            if (resource.equals(tmpResourceString)) {
                policyId = Integer.parseInt(policy.getString("id"));
                return policyId;
            }

        }
        return policyId;
    }

    /**
     * 根据服务名和策略名查找策略ID
     * @param type
     * @param resource
     * @return
     */
    public int getPolicyIdByResourceNameAndPolicyName(String type, String resource) {
        //如果不存在，返回-1，即代表新建策略
        int policyId = -1;
        //获取ranger某个服务内的所有策略
        String serviceName = getServiceName(type);
        String policyName = rangerService.formatPolicyName(type,resource);
        String policyData = getPolicyByServiceNameAndPolicyName(serviceName,policyName);
        if (policyData.isEmpty()) {
            logger.info("RangerRestService getPolicyIdByResourceNameAndPolicyName type[" + type + "] resource["+ resource +"] policyName["+ policyName +"] is null！");
            return policyId;
        }
        //ranger中的策略遍历
        JSONObject policy = JSONObject.parseObject(policyData);
        policyId = Integer.parseInt(policy.getString("id"));
        return policyId;
    }

    /**
     * 判断某个策略中的某个resource是否是单资源
     *
     * @param service     简单服务名称如hdfs
     * @param tmpResource Ranger中某策略的resource对象
     * @return
     */
    private boolean isSingleResource(String service, JSONObject tmpResource) {
        boolean result = false;
        if (service.equalsIgnoreCase("hdfs")) {
            JSONObject tmpPath = tmpResource.getJSONObject("path");
            if (tmpPath == null || tmpPath.size() == 0) {
                return result;
            }
            JSONArray tmpValues = tmpPath.getJSONArray("values");
            result = tmpValues.size() == 1 ? true : false;
        } else if (service.equalsIgnoreCase("hbase")) {
            JSONObject tmpTable = tmpResource.getJSONObject("table");
            JSONArray tmpValues = tmpTable.getJSONArray("values");
            if (tmpValues.size() > 1) {
                return result;
            }
            JSONObject tmpColumnFamily = tmpResource.getJSONObject("column-family");
            tmpValues = tmpColumnFamily.getJSONArray("values");
            if (tmpValues.size() > 1) {
                return result;
            }
            JSONObject tmpColumn = tmpResource.getJSONObject("column");
            tmpValues = tmpColumn.getJSONArray("values");
            if (tmpValues.size() > 1) {
                return result;
            }
            result = true;
        } else if (service.equalsIgnoreCase("hive")) {
            JSONObject tmpDatabase = tmpResource.getJSONObject("database");
            if (tmpDatabase == null || tmpDatabase.size() == 0) return result;
            JSONArray tmpValues = tmpDatabase.getJSONArray("values");
            if (tmpValues.size() > 1) {
                return result;
            }
            JSONObject tmpTable = tmpResource.getJSONObject("table");
            if (tmpTable == null || tmpTable.size() == 0) return result;
            tmpValues = tmpTable.getJSONArray("values");
            if (tmpValues.size() > 1) {
                return result;
            }
            JSONObject tmpColumn = tmpResource.getJSONObject("column");
            if (tmpColumn == null || tmpColumn.size() == 0) {
                return result;
            }
            tmpValues = tmpColumn.getJSONArray("values");
            if (tmpValues.size() > 1) {
                return result;
            }
            result = true;
        } else if (service.equalsIgnoreCase("yarn")) {
            JSONObject tmpQueue = tmpResource.getJSONObject("queue");
            if (tmpQueue == null || tmpQueue.size() == 0) {
                return result;
            }
            JSONArray tmpValues = tmpQueue.getJSONArray("values");
            result = tmpValues.size() == 1 ? true : false;
        } else if (service.equalsIgnoreCase("kafka")) {
            JSONObject tmpTopic = tmpResource.getJSONObject("topic");
            if (tmpTopic == null || tmpTopic.size() == 0) {
                return result;
            }
            JSONArray tmpValues = tmpTopic.getJSONArray("values");
            result = tmpValues.size() == 1 ? true : false;
        }
        return result;
    }

    /**
     * 不同组件的资源值不相同，统一转化为字符串
     *
     * @param service
     * @param tmpResource
     * @return
     */
    private String resourceFormater(String service, JSONObject tmpResource) {
        String result = "";
        if (service.equalsIgnoreCase("hdfs")) {
            JSONObject tmpPath = tmpResource.getJSONObject("path");
            JSONArray tmpValues = tmpPath.getJSONArray("values");
            result = tmpValues.getString(0);
            if (result.endsWith("/")) {
                result = result.substring(0, result.length() - 1);
            }
        } else if (service.equalsIgnoreCase("hbase")) {
            JSONObject tmpTable = tmpResource.getJSONObject("table");
            JSONArray tmpValues = tmpTable.getJSONArray("values");
            result += tmpValues.getString(0) + "|";
            JSONObject tmpColumnFamily = tmpResource.getJSONObject("column-family");
            tmpValues = tmpColumnFamily.getJSONArray("values");
            result += tmpValues.getString(0) + "|";
            JSONObject tmpColumn = tmpResource.getJSONObject("column");
            tmpValues = tmpColumn.getJSONArray("values");
            result += tmpValues.getString(0);
        } else if (service.equalsIgnoreCase("hive")) {
            JSONObject tmpDatabase = tmpResource.getJSONObject("database");
            JSONArray tmpValues = tmpDatabase.getJSONArray("values");
            result += tmpValues.getString(0) + "|";
            JSONObject tmpTable = tmpResource.getJSONObject("table");
            tmpValues = tmpTable.getJSONArray("values");
            result += tmpValues.getString(0) + "|";
            JSONObject tmpColumn = tmpResource.getJSONObject("column");
            tmpValues = tmpColumn.getJSONArray("values");
            result += tmpValues.getString(0);
        } else if (service.equalsIgnoreCase("yarn")) {
            JSONObject tmpQueue = tmpResource.getJSONObject("queue");
            JSONArray tmpValues = tmpQueue.getJSONArray("values");
            result = tmpValues.getString(0);
        } else if (service.equalsIgnoreCase("kafka")) {
            JSONObject tmpTopic = tmpResource.getJSONObject("topic");
            JSONArray tmpValues = tmpTopic.getJSONArray("values");
            result = tmpValues.getString(0);
        }
        return result;
    }

    /**
     * 根据简易类型获取Ranger完整的服务名称
     * 如输入hfds，返回cluster_101_hadoop
     *
     * @param type 类型，如hdfs/hbase/hive/yarn/kafka
     * @return
     */
    public String getServiceName(String type) {
        String name = "";
        try {
            type = type.toLowerCase();
            URL url = new URL(getRangerurl() + "/service/public/v2/api/service?serviceType=" + type + "&pageSize=1&startIndex=0");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            Map<String, Object> map = result(conn, true);
            if (!map.get("code").equals("200")) {
                logger.error((String) map.get("msg"));
            } else {
                String data = (String) map.get("data");
                JSONArray array = JSONArray.parseArray(data);
                if (array.isEmpty()) {
                    return name;
                }
                name = array.getJSONObject(0).getString("name");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService getServiceName type[" + type + "] error.");
        }
        return name;
    }

    /**
     * 判断某个资源中是否包含特定用户
     * @param type
     * @param resource
     * @param user
     * @return
     */
    public boolean isResourceContainUser(String type, String resource, String user) {
//        boolean result = false;
        try {
           int policyId = getPolicyIdByResourceItems(type,resource);
           if (policyId < 0) {
               logger.info("RangerRestService isResourceContainUser type[" + type + "] resource["+ resource +"] is not exist");
               return false;
           }
           String policyData = getPolicyById(policyId+"");
           JSONObject object = JSONObject.parseObject(policyData);
           JSONArray policyItemsArray = object.getJSONArray("policyItems");
           for (int i=0; i<policyItemsArray.size(); i++) {
               JSONObject tmpObject = policyItemsArray.getJSONObject(i);
               boolean isUserExists = isResourceItemContainUser(tmpObject,user);
               if (isUserExists) {
//                   result = true;
                   return true;
               }
           }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new ApiException("RangerRestService isResourceContainUser type[" + type + "] resource["+ resource +"] user["+ user +"] error.");
        }
        return false;
    }

    /**
     * 判断策略中某个item信息中是否包含用户
     * @param object
     * @param user
     * @return
     */
    private boolean isResourceItemContainUser (JSONObject object, String user) {
//        boolean result = false;
        JSONArray userArray = object.getJSONArray("users");
        if (userArray == null){
            return false;
        }
        for (int i=0; i<userArray.size(); i++) {
            String tmpUser = userArray.getString(i);
//            if (tmpUser.equals(user)) {
            if (user.equals(tmpUser)){
//                result = true;
                return true;
            }
        }
        return false;
    }


}
